package com.ticket.sass.admin.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.admin.business.OrderTicketBusiness;
import com.ticket.sass.admin.dto.input.order.OrderTicketListInput;
import com.ticket.sass.admin.dto.input.order.TicketRefundInput;
import com.ticket.sass.admin.dto.output.order.CouponOutput;
import com.ticket.sass.admin.dto.output.order.OrderDataModel;
import com.ticket.sass.admin.dto.output.order.OrderTicketListOutput;
import com.ticket.sass.admin.dto.output.order.TicketOutput;
import com.ticket.sass.admin.dto.output.pricecheme.PriceSchemeSimpOutput;
import com.ticket.sass.admin.manager.OrderCommodityManager;
import com.ticket.sass.admin.manager.OrderManager;
import com.ticket.sass.admin.manager.OrderTicketManager;
import com.ticket.sass.admin.model.FilmSaleModel;
import com.ticket.sass.admin.service.impl.*;
import com.ticket.sass.common.entity.tenant.*;
import com.ticket.sass.common.entity.tenant.enums.OrderPayStatus;
import com.ticket.sass.common.entity.tenant.enums.OrderPayType;
import com.ticket.sass.common.entity.tenant.enums.OrderTicketStatus;
import com.ticket.sass.common.entity.tenant.enums.OrderType;
import com.ticket.sass.common.exception.enums.ErrorCode;
import com.ticket.sass.common.exception.exception.BadRequestException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2024-03-14 14:23
 */
@Slf4j
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class OrderTicketBusinessImpl implements OrderTicketBusiness {
    final OrderManager orderManager;
    final UserServiceImpl userService;
    final OrderServiceImpl orderService;
    final OrderTicketServiceImpl service;
    final CinemaServiceImpl cinemaService;
    final OrderPayServiceImpl orderPayService;
    final OrderTicketManager orderTicketManager;
    final OrderMixedServiceImpl orderMixedService;
    final PriceSchemeServiceImpl priceSchemeService;
    final OrderCommodityManager orderCommodityManager;
    final FilmScheduleServiceImpl filmScheduleService;
    final OrderCouponMapServiceImpl orderCouponMapService;
    final OrderFilmSaleMapServiceImpl orderFilmSaleMapService;
    final OrderTicketDetailServiceImpl orderTicketDetailService;
    
    @Override
    public OrderDataModel<OrderTicketListOutput> list(OrderTicketListInput input) {
        List<Long> inputUserIds = userService.getUserIdByCellphone(input.getCellphone());
        if (StrUtil.isNotEmpty(input.getCellphone()) && inputUserIds.isEmpty()){
            return new OrderDataModel<>();
        }
        input.setUserIds(inputUserIds);
        
        List<Long> orderIdsBy = orderCouponMapService.orderIdsBy(input.getCouponIds());
        if (CollectionUtil.isNotEmpty(input.getCouponIds()) && orderIdsBy.isEmpty()){
            return new OrderDataModel<>();
        }
        input.setIds(orderIdsBy);
        
        IPage<OrderTicketEntity> page = service.iPage(input);
        List<OrderTicketListOutput> outputs = page.getRecords().stream().map(OrderTicketListOutput::new).collect(Collectors.toList());
        
        // 获取订单ID列表
        List<Long> orderIds = outputs.stream()
            .map(OrderTicketListOutput::getOrderId)
            .collect(Collectors.toList());
        
        List<Long> orderTicketIds = outputs.stream().map(OrderTicketListOutput::getId).collect(Collectors.toList());
        
        List<Long> priceSchemeId = outputs.stream()
            .map(OrderTicketListOutput::getPriceSchemeId)
            .collect(Collectors.toList());
        
        Map<Long, PriceSchemeEntity> longPriceSchemeEntityMap = priceSchemeService.mapByIds(priceSchemeId);
        
        // 根据订单ID列表查询对应的优惠券
        Map<Long, List<OrderCouponMapEntity>> orderCouponMapByOrderIds = orderCouponMapService.getOrderCouponMapByOrderIds(orderIds);
        
        Map<Long, List<TicketOutput>> ticketDetailsByOrderTicketIds = orderTicketDetailService.getTicketDetailsByOrderTicketIds(orderTicketIds);
        
        // 提取用户ID列表
        List<Long> userIds = outputs.stream()
            .map(OrderTicketListOutput::getUserId)
            .collect(Collectors.toList());
        
        Map<Long, UserEntity> longUserEntityMap = userService.mapByIds(userIds);
        
        
        Map<Long, OrderEntity> orderEntityMap = orderService.mapByIds(orderIds);
        
        
        outputs.forEach(o -> {
            o.setUsername(longUserEntityMap.getOrDefault(o.getUserId(), new UserEntity()).getNickname());
            o.setCellphone(longUserEntityMap.getOrDefault(o.getUserId(), new UserEntity()).getCellphone());
            
            if (o.getUseCoupon()) {
                List<OrderCouponMapEntity> couponMapEntities = orderCouponMapByOrderIds.getOrDefault(o.getOrderId(), new ArrayList<>());
                List<CouponOutput> couponOutputs = couponMapEntities.stream()
                    .map(d -> new CouponOutput(d.getCouponId(), d.getCouponName(), d.getDiscountAmount()))
                    .collect(Collectors.toList());
                // 将商品输出对象列表设置到订单商品输出对象中
                o.setCoupons(couponOutputs);
            } else {
                o.setCoupons(new ArrayList<>());
            }
            o.setTickets(ticketDetailsByOrderTicketIds.getOrDefault(o.getId(), new ArrayList<>()));
            
            
            PriceSchemeEntity orDefault = longPriceSchemeEntityMap.get(o.getPriceSchemeId());
            if (orDefault != null){
                o.setPriceSchemes(new PriceSchemeSimpOutput(orDefault.getId(), orDefault.getTitle(), orDefault.getSalePrice()));
            }
            
            OrderEntity order = orderEntityMap.getOrDefault(o.getOrderId(), new OrderEntity());
            o.setRefundRemark(order.getRefundRemark());
            
        });
        
        OrderDataModel orderDataModel = new OrderDataModel();
        
        orderDataModel.setTotal(page.getTotal());
        orderDataModel.setList(outputs);
        
        List<OrderTicketEntity> list = service.list(input);
        List<Long> orderIdList = list.stream().map(OrderTicketEntity::getOrderId).collect(Collectors.toList());
        
        OrderEntity order = orderService.dateCount(OrderType.TICKET.getValue(), null, orderIdList);
        
        if (Objects.nonNull(order)){
            orderDataModel.setSumPayPrice(order.getSumPayPrice());
            orderDataModel.setWxSumPayPrice(order.getWxSumPayPrice());
            orderDataModel.setMemberSumPayPrice(order.getMemberSumPayPrice());
            orderDataModel.setCount(order.getTotalRecords());
            orderDataModel.setTicketCount(summarizeTicketCount(list, null));
            orderDataModel.setTicketAmount(summarizeTicketPrice(list, null));
        }
        
        OrderEntity refundOrder = orderService.dateCount(OrderType.TICKET.getValue(), OrderPayStatus.REFUND_SUCCESS.getValue(), orderIdList);
        
        if (Objects.nonNull(refundOrder)){
            orderDataModel.setRefundAmount(refundOrder.getSumPayPrice());
            orderDataModel.setRefundCount(refundOrder.getTotalRecords());
            orderDataModel.setRefundWxAmount(refundOrder.getWxSumPayPrice());
            orderDataModel.setRefundMemberAmount(refundOrder.getMemberSumPayPrice());
            orderDataModel.setRefundTicketCount(summarizeTicketCount(list, OrderTicketStatus.REFUND_SUCCESS));
        }
        return orderDataModel;
    }
    
    /**
     * 根据给定的订单ID列表，汇总退票数量。
     *
     * @param list          包含影票订单的列表
     * @return 汇总的退票数量
     */
    public Integer summarizeTicketCount(List<OrderTicketEntity> list, OrderTicketStatus status) {
        // 使用流过滤出orderId在refundOrderIds列表中的OrderTicketEntity对象
        List<OrderTicketEntity> refundTickets = list.stream()
            .filter(ticket -> status == null || ticket.getTicketStatus() == status)
            .collect(Collectors.toList());
        
        // 汇总退票数量
        Integer totalRefundedTickets = refundTickets.stream()
            .mapToInt(OrderTicketEntity::getTicketCount)
            .sum();
        
        return totalRefundedTickets;
    }
    
    
    /**
     * 根据给定的订单ID列表，汇总退票金额。
     *
     * @param list          包含影票订单的列表
     * @param status        退票状态，如果为null，则汇总所有订单的退票数量
     * @return 汇总的退票数量
     */
    public BigDecimal summarizeTicketPrice(List<OrderTicketEntity> list, OrderTicketStatus status) {
        // 使用流过滤出符合条件的OrderTicketEntity对象
        List<OrderTicketEntity> refundTickets = list.stream()
            .filter(ticket -> isRefundStatus(ticket, status))
            .collect(Collectors.toList());
        
        // 汇总退票金额
        BigDecimal totalRefundedAmount = refundTickets.stream()
            .map(OrderTicketEntity::getTicketPrice) // 假设getTicketPrice返回的是BigDecimal类型
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        return totalRefundedAmount;
    }
    
    private boolean isRefundStatus(OrderTicketEntity ticket, OrderTicketStatus status) {
        return status == null || ticket.getTicketStatus() == status;
    }
    
    @Override
    public void refund(TicketRefundInput input) {
        // 校验订单ID
        validateOrderId(input.getOrderId());
        
        OrderEntity order = orderService.getById(input.getOrderId());
        
        // 混合订单
        if (order.getOrderMixedId() != 0){
            List<OrderEntity> orderEntities = orderService.listByInMixedId(order.getOrderMixedId());
            orderEntities.forEach(it -> {
                it.setRefundRemark(input.getRemark());
                if (it.getType() == OrderType.TICKET){
                    orderTicketManager.refund(it, OrderTicketManager.RefundType.Companion.fromType(input.getType()), input.getRefundCoupon());
                } else {
                    orderCommodityManager.refund(it, input.getRefundCoupon());
                }
            });
            
            OrderMixedEntity orderMixed = orderManager.updateOrderMixedStatus(order.getOrderMixedId());
            
            // 如果是微信支付
            if (order.getPayType() == OrderPayType.WXA){
                orderManager.refundToWeChat(order, orderMixed);
            }
            // 单独订单
        } else {
            order.setRefundRemark(input.getRemark());
            orderTicketManager.refund(order, OrderTicketManager.RefundType.Companion.fromType(input.getType()), input.getRefundCoupon());
            
            // 如果是微信支付
            if (order.getPayType() == OrderPayType.WXA){
                orderManager.refundToWeChat(order, null);
            }
        }
    }
    
    @Override
    public void generateTicketStatistics(Long cinemaId) {
        // 获取影院实体
        CinemaEntity cinemaEntity = cinemaService.getById(cinemaId);
        
        // 2.1 根据影院id查询order_tickets表，按排期ID聚合统计
        List<Map<String, Object>> ticketStats = service.getTicketStatsByCinemaId(cinemaId, LocalDate.now().minusDays(1), LocalDate.now());
        
        // 聚合后的影票统计信息
        Map<Long, FilmSaleModel> filmSaleMap = new HashMap<>();
        // 排期ID
        List<Long> scheduleIds = new ArrayList<>();
        
        // 遍历查询结果
        for (Map<String, Object> stat : ticketStats) {
            Long filmScheduleId = stat.get("film_schedule_id") != null ? ((Number) stat.get("film_schedule_id")).longValue() : 0L;
            scheduleIds.add(filmScheduleId);
            
            Integer ticketCount = stat.get("ticket_count") != null ? ((Number) stat.get("ticket_count")).intValue() : 0;
            BigDecimal price = stat.get("price") != null ? (BigDecimal) stat.get("price") : BigDecimal.ZERO;
            filmSaleMap.put(filmScheduleId, new FilmSaleModel(ticketCount, price));
        }
        
        // 2.2 查询排期与影片版本 排期ID到影片ID的映射
        Map<Long, Long>  scheduleToFilmMap = filmScheduleService.getFilmSchedulesByIds(scheduleIds);
        
        
        // 2.3 遍历统计结果，返回影片与数量
        Map<Long, FilmSaleModel> filmCountMap = filmSaleMap.entrySet().stream()
            .collect(Collectors.toMap(
                entry -> scheduleToFilmMap.get(entry.getKey()),
                Map.Entry::getValue,
                this::mergeFilmSaleModels,
                HashMap::new
            ));
        
        // 2.4 新增记录到结果表
        List<OrderFilmSaleMapEntity> list = filmCountMap.entrySet().stream()
            .map(entry -> new OrderFilmSaleMapEntity(
                entry.getKey(),
                LocalDate.now().minusDays(1),
                entry.getValue().getTicketCount(),
                entry.getValue().getPrice(),
                cinemaId,
                cinemaEntity.getTenantId()
            ))
            .collect(Collectors.toList());
        
        // 批量保存结果到数据库
        orderFilmSaleMapService.saveBatch(list);
    }
    
    private FilmSaleModel mergeFilmSaleModels(FilmSaleModel existing, FilmSaleModel replacement) {
        existing.setTicketCount(existing.getTicketCount() + replacement.getTicketCount());
        existing.setPrice(existing.getPrice().add(replacement.getPrice()));
        return existing;
    }
    
    private void validateOrderId(Long id) {
        if (orderService.isEmpty(id)) {
            throw new BadRequestException(
                ErrorCode.RECORD_NOT_EXIST,
                ErrorCode.RECORD_NOT_EXIST.getReasonPhrase()
            );
        }
    }
}
